﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Pipes.Queries.Model.Query;

namespace Pipes.Queries.Execution
{
  internal static class ExecUtils
  {
    public static bool AssertCount<T>(IList<T> args, int count, string name)
    {
      if (args.Count != count) throw new InvalidOperationException(string.Format("{0} requires exactly {1} arguments.  {2} arguments were found.", name, count, args.Count));
      return true;
    }
    public static bool AssertMinCount<T>(IList<T> args, int count, string name)
    {
      if (args.Count < count) throw new InvalidOperationException(string.Format("{0} requires exactly {1} arguments.  {2} arguments were found.", name, count, args.Count));
      return true;
    }
    public static IList<object> EvalArgs(IList<IExpression> args, out bool anyNull)
    {
      var result = new List<object>(args.Count);
      anyNull = false;
      foreach (var arg in args)
      {
        result.Add(arg.Evaluate());
        if (IsNull(result.Last())) anyNull = true;
      }
      return result;
    }
    public static decimal GetDecimal(object x)
    {
      if (x is decimal)
      {
        return (decimal)x;
      }
      else if (x is bool)
      {
        return ((bool)x ? 1 : 0);
      }
      else
      {
        throw new ArgumentException();
      }
    }
    public static long GetLong(object x)
    {
      if (x is decimal)
      {
        var dec = (decimal)x;
        if (Math.Round(dec, 25) == Math.Round(dec)) return (long)dec;
        throw new ArgumentException(string.Format("Cannot convert {0} to integer.", dec));
      }
      else if (x is bool)
      {
        return ((bool)x ? 1 : 0);
      }
      else
      {
        throw new ArgumentException();
      }
    }
    public static bool IsTrue(object x)
    {
      return (x is bool && (bool)x);
    }
    public static bool IsNull(object x)
    {
      return (x == null || x == DBNull.Value);
    }
    public static bool TryGetBool(object x, out bool value)
    {
      if (x is decimal)
      {
        value = (Math.Round((decimal)x, 25) != 0);
        return true;
      }
      else if (x is bool)
      {
        value = (bool)x;
        return true;
      }
      else
      {
        value = false;
        return false;
      }
    }
  }
}
